using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using Forecast.Database;

namespace Forecast.Business
{
    public class Portfolio
    {
        #region Enums

        public enum Columns
        {
            None,
            HoldingId,
            PredictionId,
            Ticker,
            Prediction,
            EndDate,
            ActivityLevel,
            TotalNumStocks,
            NumStocksForSale,
            NumStocksForBuy,
            ValuePerStock,
            TotalValue,
            LastChange,
            Result
        }

        #endregion
        #region Variables

        private Player _player;
        private Activity _activity;

        #endregion
        #region Constructors

        internal Portfolio(Player player, Activity activity)
        {
            _player = player;
            _activity = activity;
        }

        #endregion
        #region Interface

        private int GetNumStocksForBuy(Holding holding, IList<Offer> offers)
        {
            int numStocksForBuy = 0;

            foreach (Offer offer in offers)
            {
                if (!offer.IsActive)
                    continue;
                if (offer.PredictionId != holding.PredictionId)
                    continue;
                if (!offer.IsBuy)
                    continue;
                numStocksForBuy += offer.NumPredictions;
            }

            return numStocksForBuy;
        }

        internal DataTable GetPortfolio(IList<Prediction> predictions, IList<Offer> offers, IList<Holding> holdings)
        {

            DataTable table = GetEmptyDataTableForPortfolio();

            foreach (Holding holding in holdings)
            {
                DataRow row = table.NewRow();

                Prediction prediction = GetPrediction(holding.PredictionId, predictions);
                if (prediction == null)
                    continue;

                int totalNumStocks = GetTotalNumStocks(holding, offers);
                int numStocksForSale = GetNumStocksForSale(holding, offers);
                int numStocksForBuy = GetNumStocksForBuy(holding, offers);
                if (totalNumStocks == 0 && numStocksForBuy == 0)
                    continue;

                row[Columns.HoldingId.ToString()] = holding.Id;
                row[Columns.PredictionId.ToString()] = holding.PredictionId;
                row[Columns.Ticker.ToString()] = prediction.Ticker;
                row[Columns.Prediction.ToString()] = prediction.ShortDescription;
                row[Columns.EndDate.ToString()] = prediction.EndDate;
                row[Columns.ActivityLevel.ToString()] = GetActivityLevel(holding.PredictionId, offers);                
                row[Columns.TotalNumStocks.ToString()] = totalNumStocks;
                row[Columns.NumStocksForSale.ToString()] = numStocksForSale;
                row[Columns.NumStocksForBuy.ToString()] = numStocksForBuy;
                row[Columns.ValuePerStock.ToString()] = prediction.LastValue;
                row[Columns.TotalValue.ToString()] = GetTotalValue(holding, offers, prediction.LastValue);
                row[Columns.LastChange.ToString()] = prediction.LastChange;
                row[Columns.Result.ToString()] = _activity.GetResultForPlayer(_player.Id, holding.PredictionId);

                table.Rows.Add(row);
            }

            return table;
        }
        #endregion
        #region Helper methods

        private int GetTotalValue(Holding holding, IList<Offer> offers, int lastValue)
        {
            int totalValue = 0;

            totalValue += holding.NumPredictions * lastValue;
            foreach (Offer offer in offers)
            {
                if (!offer.IsActive)
                    continue;
                if (offer.PredictionId != holding.PredictionId)
                    continue;
                if (offer.IsBuy)
                    continue;
                int price = lastValue;
                if (price > offer.Price)
                    price = offer.Price;
                totalValue += price * offer.NumPredictions;
            }

            return totalValue;
        }

        private int GetNumStocksForSale(Holding holding, IList<Offer> offers)
        {
            int numStocksForSale = 0;

            foreach (Offer offer in offers)
            {
                if (!offer.IsActive)
                    continue;
                if (offer.PredictionId != holding.PredictionId)
                    continue;
                if (offer.IsBuy)
                    continue;
                numStocksForSale += offer.NumPredictions;
            }

            return numStocksForSale;
        }

        private int GetTotalNumStocks(Holding holding, IList<Offer> offers)
        {
            int totalNumStocks = 0;

            totalNumStocks += holding.NumPredictions;
            foreach (Offer offer in offers)
            {
                if (!offer.IsActive)
                    continue;
                if (offer.PredictionId != holding.PredictionId)
                    continue;
                if (offer.IsBuy)
                    continue;
                totalNumStocks += offer.NumPredictions;
            }

            return totalNumStocks;
        }

        private int GetActivityLevel(int predictionId, IList<Offer> offers)
        {
            int activityLevel = 0;

            foreach (Offer offer in offers)
            {
                if (offer.PredictionId != predictionId)
                    continue;
                if (offer.PlayerId == _player.Id)
                    activityLevel++;
                else
                {
                    if (offer.IsAccepted && offer.AcceptorId == _player.Id)
                        activityLevel++;
                }
            }

            return activityLevel;
        }

        private Prediction GetPrediction(int predictionId, IList<Prediction> predictions)
        {
            foreach (Prediction prediction in predictions)
            {
                if (prediction.Id == predictionId)
                    return prediction;
            }
            return null;
        }

        private DataTable GetEmptyDataTableForPortfolio()
        {
            DataTable dataTable = new DataTable("Portfolio");

            DataColumn columnHoldingId = new DataColumn();
            columnHoldingId.ColumnName = Columns.HoldingId.ToString();
            columnHoldingId.DataType = typeof(int);
            dataTable.Columns.Add(columnHoldingId);

            DataColumn columnPredictionId = new DataColumn();
            columnPredictionId.ColumnName = Columns.PredictionId.ToString();
            columnPredictionId.DataType = typeof(int);
            dataTable.Columns.Add(columnPredictionId);

            DataColumn columnTicker = new DataColumn();
            columnTicker.ColumnName = Columns.Ticker.ToString();
            columnTicker.DataType = typeof(string);
            dataTable.Columns.Add(columnTicker);

            DataColumn columnPrediction = new DataColumn();
            columnPrediction.ColumnName = Columns.Prediction.ToString();
            columnPrediction.DataType = typeof(string);
            dataTable.Columns.Add(columnPrediction);

            DataColumn columnEndDate = new DataColumn();
            columnEndDate.ColumnName = Columns.EndDate.ToString();
            columnEndDate.DataType = typeof(DateTime);
            dataTable.Columns.Add(columnEndDate);

            DataColumn columnActivityLevel = new DataColumn();
            columnActivityLevel.ColumnName = Columns.ActivityLevel.ToString();
            columnActivityLevel.DataType = typeof(int);
            dataTable.Columns.Add(columnActivityLevel);

            DataColumn columnTotalNumStocks = new DataColumn();
            columnTotalNumStocks.ColumnName = Columns.TotalNumStocks.ToString();
            columnTotalNumStocks.DataType = typeof(int);
            dataTable.Columns.Add(columnTotalNumStocks);

            DataColumn columnNumStocksForSale = new DataColumn();
            columnNumStocksForSale.ColumnName = Columns.NumStocksForSale.ToString();
            columnNumStocksForSale.DataType = typeof(int);
            dataTable.Columns.Add(columnNumStocksForSale);

            DataColumn columnNumStocksForBuy = new DataColumn();
            columnNumStocksForBuy.ColumnName = Columns.NumStocksForBuy.ToString();
            columnNumStocksForBuy.DataType = typeof(int);
            dataTable.Columns.Add(columnNumStocksForBuy);

            DataColumn columnValuePerStock = new DataColumn();
            columnValuePerStock.ColumnName = Columns.ValuePerStock.ToString();
            columnValuePerStock.DataType = typeof(int);
            dataTable.Columns.Add(columnValuePerStock);

            DataColumn columnTotalValue = new DataColumn();
            columnTotalValue.ColumnName = Columns.TotalValue.ToString();
            columnTotalValue.DataType = typeof(int);
            dataTable.Columns.Add(columnTotalValue);

            DataColumn columnLastChange = new DataColumn();
            columnLastChange.ColumnName = Columns.LastChange.ToString();
            columnLastChange.DataType = typeof(double);
            dataTable.Columns.Add(columnLastChange);

            DataColumn columnResult = new DataColumn();
            columnResult.ColumnName = Columns.Result.ToString();
            columnResult.DataType = typeof(int);
            dataTable.Columns.Add(columnResult);

            return dataTable;
        }

        #endregion
    }
}
